use log::error;
use once_cell::sync::OnceCell;
use std::{
    backtrace::Backtrace,
    panic::{self, PanicHookInfo},
    path::PathBuf,
    sync::{Arc, Mutex},
};

use anyhow::anyhow;
use anyhow::{Ok, Result};

const LOG_FILE_NAME: &str = "config/log4rs.yml";

static INITED: OnceCell<Arc<Mutex<bool>>> = OnceCell::new();

static LOG4RS_YML: &[u8] = include_bytes!("../resources/log4rs.yml");
pub fn init() -> Result<()> {
    let mut init = INITED
        .get_or_init(|| Arc::new(Mutex::new(false)))
        .lock()
        .or_else(|e| Err(anyhow!("Failed to lock mutex: {}", e)))?;
    if *init {
        return Ok(());
    }

    // 判断当前运行目录下, 文件log4rs.yml是否存在
    if !std::path::Path::new(LOG_FILE_NAME).exists() {
        let target_path = PathBuf::from(LOG_FILE_NAME);
        std::fs::write(target_path, LOG4RS_YML).or_else(|e| Err(anyhow!("Failed to write log4rs.yml: {}", e)))?;
    }

    log4rs::init_file(LOG_FILE_NAME, Default::default())?;

    // 设置 panic 钩子
    panic::set_hook(Box::new(|info: &PanicHookInfo<'_>| {
        if let Some(location) = info.location() {
            error!("panic at {}, {}:{}", location.file(), location.line(), location.column());
        } else {
            error!("panic occurred");
        }

        if let Some(message) = info.payload().downcast_ref::<&str>() {
            error!("panic message: {}", message);
        } else if let Some(message) = info.payload().downcast_ref::<String>() {
            error!("panic message: {}", message);
        }

        let backtrace = Backtrace::force_capture();
        error!("Caught panic: {:?}", info);
        error!("Backtrace: {:?}", backtrace);
    }));

    *init = true;
    Ok(())
}
